#!/bin/bash
# -----------------------------------------------------------------------------
# Creates a spine-leaf fabric with large number of hosts using null providers
#
# Default setup as follows:
#   2 spines, can potentially be few more
#   12 leaves in total
#       2 leaf pair
#       8 non-paired
#   Host per leaf up to 1K
#
# -----------------------------------------------------------------------------

function usage {
    echo "usage: $(basename $0) [options] [onos-ip]"
    echo ""
    echo "Options:"
    echo "  -s spines"
    echo "  -l spineLinks"
    echo "  -S serviceHosts"
    echo "  -G gateways"
    echo "  -a accessLeaves"
    echo "  -A accessHosts"
    exit 1
}

spines=2
spineLinks=2
serviceLeafGroups="A B"
serviceHosts=10
accessLeaves=8
accessHosts=100
gateways=2

# Scan arguments for user/password or other options...
while getopts s:l:a:A:S:G:?h o; do
    case "$o" in
        s) spines=$OPTARG;;
        l) spineLinks=$OPTARG;;
        a) accessLeaves=$OPTARG;;
        A) accessHosts=$OPTARG;;
        S) serviceHosts=$OPTARG;;
        G) gateways=$OPTARG;;
        *) usage $0;;
    esac
done

spinePorts=48
let leafPorts=serviceHosts+8     # derive service ports from service hosts
let accessPorts=accessHosts+8    # derive access ports from access hosts

let OPC=$OPTIND-1
shift $OPC

# config
node=${1:-$OCI}


# Create the script of ONOS commands first and then execute it all at once.
export CMDS="/tmp/access-onos.cmds"
rm $CMDS

function sim {
    echo "$@" >> $CMDS
}

# Create spines
for spine in $(seq 1 $spines); do
    sim "null-create-device switch Spine-${spine} ${spinePorts}"
done

gwIps=""

# Create 2 leaf pairs with dual links to the spines and a link between the pair
for pair in $serviceLeafGroups; do
    [ $pair = A ] && l1=1 || l1=3
    [ $pair = A ] && l2=2 || l2=4
    sim "null-create-device switch Leaf-${pair}1 ${leafPorts}"
    sim "null-create-device switch Leaf-${pair}2 ${leafPorts}"
    sim "null-create-link direct Leaf-${pair}1 Leaf-${pair}2"

    for spine in $(seq 1 $spines); do
        for link in $(seq 1 $spineLinks); do
            sim "null-create-link direct Spine-${spine} Leaf-${pair}1"
            sim "null-create-link direct Spine-${spine} Leaf-${pair}2"
        done
    done

    # Create gateways attached to each leaf group; multi-homed to each leaf in the pair
    [ $pair = A ] && pn=1 || pn=2
    for gw in $(seq 1 $gateways); do
        sim "null-create-host Leaf-${pair}1,Leaf-${pair}2 10.${pn}.0.${gw}"
        gwIps="${gwIps}|10.${pn}.0.${gw}"
    done

    # Create hosts for each leaf group; multi-homed to each leaf in the pair
    [ $pair = A ] && offset=-400 || offset=400
    for host in $(seq 1 $serviceHosts); do
        sim "null-create-host Leaf-${pair}1,Leaf-${pair}2 10.${pn}.1.${host}"
    done
done

# Create single access leafs with dual links to the spines
for access in $(seq $accessLeaves); do
    sim "null-create-device switch Access-${access} ${accessPorts}"

    for spine in $(seq 1 $spines); do
        for link in $(seq 1 $spineLinks); do
            sim "null-create-link direct Spine-${spine} Access-${access}"
        done
    done

    # Create hosts for each access single leaf
    sim "null-create-hosts Access-${access} 10.1${access}.1.*" $accessHosts
    # sim "null-create-hosts Access-${access} 10.1${access}.2.*" $accessHosts
done


# make sure null providers are activated and any running simulation is stopped
onos ${node} app activate org.onosproject.null
sleep 2
onos ${node} null-simulation stop

# wait until the masterships clear-out across the cluster
while onos ${node} masters | grep -qv " 0 devices"; do sleep 1; done

# clean-up
onos ${node} wipe-out please
sleep 1

# start custom simulation..
onos ${node} null-simulation start custom
sleep 2

# Add devices, links, and hosts
cat $CMDS | onos ${node}

# After the network is created, add network config to assign roles to gateway IPs.
cfg=""
for gw in $(onos ${node} hosts | egrep "${gwIps/|/}" | cut -d, -f1 | cut -d= -f2); do
    cfg="${cfg}, \"$gw\": { \"basic\": { \"uiType\" : \"router\", \"roles\": [ \"gateway\" ]}}"
done
echo "{ \"hosts\": { ${cfg/,/} }}" > $CMDS

onos-netcfg ${node} $CMDS